package com.bestv.engine.recommender;

import com.bestv.engine.sorter.Sorter;
import com.bestv.engine.sorter.Sorters;
import com.bestv.utils.common.Reloadable;
import com.bestv.utils.config.GlobalSettings;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

/**
 * Created by Henry on 14-5-23.
 */
public class RecommenderManager extends Reloadable {
    private Logger logger = LoggerFactory.getLogger(getClass());

    private Map<String, Model> modelMap;
    private Map<String, Sorter> sorterMap;
    private List<RecommenderRouter> recommenderRouters;
    private Map<String, Recommender> recommenderMap;

    private static RecommenderManager instance;

    public static synchronized RecommenderManager getInstance() {
        if (instance == null) {
            instance = new RecommenderManager();
        }
        return instance;
    }

    private RecommenderManager() {
        modelMap = new HashMap<String, Model>();
        sorterMap = new HashMap<String, Sorter>();
        recommenderRouters =  new ArrayList<RecommenderRouter>();
        recommenderMap = new HashMap<String, Recommender>();
        reload();
        setConfigFile(GlobalSettings.getInstance().getRecommenderConfigFile());
        start();
    }

    @Override
    protected void reload() {
        Document document = null;
        try {
            File file = new File(GlobalSettings.getInstance().getRecommenderConfigFile());
            SAXReader saxReader = new SAXReader();
            document = saxReader.read(file);
        } catch (DocumentException e) {
            logger.error("Error on document reading.", e);
        }

        assert document != null;
        Element rootElement = document.getRootElement();

        Element models = rootElement.element("models");
        Iterator modelIterator = models.elementIterator();
        while (modelIterator.hasNext()) {
            Element element = (Element) modelIterator.next();
            Model model = new Model();
            model.setName(element.attributeValue("name"));
            model.setSize(element.attributeValue("size"));
            model.setRandomSelect(element.attributeValue("isRandomSelect"));
            model.setRandomSort(element.attributeValue("isRandomSort"));
            model.setClassName(element.getStringValue());
            modelMap.put(model.getName(), model);
        }

        Element sorters = rootElement.element("sorters");
        Iterator sorterIterator = sorters.elementIterator();
        while (sorterIterator.hasNext()) {
            Element element = (Element) sorterIterator.next();
            String name = element.attributeValue("name");
            String className = element.getStringValue();
            Sorter sorter = null;
            try {
                sorter = (Sorter) Class.forName(className).newInstance();
            } catch (ClassNotFoundException e) {
                logger.error("Class {} not found.", className, e);
            } catch (InstantiationException e) {
                logger.error("Error on instantiation.", e);
            } catch (IllegalAccessException e) {
                logger.error("Error on illegal access.", e);
            }
            sorterMap.put(name, sorter);
        }

        Element recommenders = rootElement.element("recommenders");
        Iterator recommenderIterator = recommenders.elementIterator();
        while (recommenderIterator.hasNext()) {
            Element element = (Element) recommenderIterator.next();
            RecommenderRouter recommenderRouter = new RecommenderRouter();
            recommenderRouter.setName(element.attributeValue("name"));
            recommenderRouter.setMethod(element.attributeValue("method"));
            recommenderRouter.setTypeIds(element.attributeValue("type_ids"));
            recommenderRouter.setUserGroups(element.attributeValue("user_groups"));
            recommenderRouters.add(recommenderRouter);

            Recommender recommender = new Recommender();
            recommender.setName(recommenderRouter.getName());
            if (element.element("model_chain") != null) {
                List<Model> modelChain = new ArrayList<Model>();
                String[] modelList = element.element("model_chain").getStringValue().split(",");
                for (String model : modelList) {
                    modelChain.add(modelMap.get(model));
                }
                recommender.setModelChain(modelChain);
            }
            if (element.element("sorter_chain") != null) {
                Sorters sorterChain = new Sorters();
                String[] sorterList = element.element("sorter_chain").getStringValue().split(",");
                for (String sorter : sorterList) {
                    sorterChain.add(sorterMap.get(sorter));
                }
                recommender.setSorterChain(sorterChain);
            }
            recommenderMap.put(recommender.getName(), recommender);
        }
    }

    public Recommender getRecommender(String method, Integer typeId, String userGroup) {
        String name = null;
        for (RecommenderRouter recommenderRouter : recommenderRouters) {
            String thisMethod = recommenderRouter.getMethod();
            Set<Integer> typeIds = recommenderRouter.getTypeIds();
            Set<String> userGroups = recommenderRouter.getUserGroups();
            if (!thisMethod.equals(method)
                || (typeIds != null && !typeIds.contains(typeId))
                || (userGroups != null && !userGroups.contains(userGroup))) {
                continue;
            }
            name = recommenderRouter.getName();
            break;
        }
        return recommenderMap.get(name);
    }
}
